Packages

library(tidyverse)
── Attaching packages ───────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──
✔ ggplot2 3.0.0     ✔ purrr   0.2.5
✔ tibble  1.4.2     ✔ dplyr   0.7.6
✔ tidyr   0.8.1     ✔ stringr 1.3.1
✔ readr   1.1.1     ✔ forcats 0.3.0
── Conflicts ──────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
library(sf)
Linking to GEOS 3.6.2, GDAL 2.3.1, proj.4 5.1.0
library(plotly)

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
library(leaflet)

Functions

`%<>%` <- magrittr::`%<>%`

API tokens

mapbox <- "https://api.mapbox.com/styles/v1/robertmitchellv/cipr7teic001aekm72dnempan/tiles/256/{z}/{x}/{y}@2x?access_token=pk.eyJ1Ijoicm9iZXJ0bWl0Y2hlbGx2IiwiYSI6ImNpcHI2cXFnbTA3MHRmbG5jNWJzMzJtaDQifQ.vtvgLokcc_EJgnWVPL4vXw"

Data

Read the affordable housing data

housing <- read_csv("../data/raw/Affordable_Rental_Housing_Developments.csv") %>%
  janitor::clean_names()
Parsed with column specification:
cols(
  `Community Area Name` = col_character(),
  `Community Area Number` = col_integer(),
  `Property Type` = col_character(),
  `Property Name` = col_character(),
  Address = col_character(),
  `Zip Code` = col_integer(),
  `Phone Number` = col_character(),
  `Management Company` = col_character(),
  Units = col_integer(),
  `X Coordinate` = col_double(),
  `Y Coordinate` = col_double(),
  Latitude = col_double(),
  Longitude = col_double(),
  Location = col_character()
)

Check for problems

problems(housing)

Read the geo data

geo_data <- read_sf(
  dsn = "../data/geo/chicago_boundaries_community_areas.geojson",
  layer = "chicago_boundaries_community_areas"
)

Tidy

Get summary totals

  • Before joining data, we need totals for the map, e.g., how many veterans projects in a particular community?
    • There are 24 different property types; most of it is senior and family, maybe we can simplify?
    • There are 146 different developpers with the top 17 all developping and managing 5+ affordable housing properties

Look for categories

housing %>% 
  count(property_type) 

This is subjective, but it is also important to remember that all classification or categorization is subjective–it’s a critical choice and important to remember when working with data. Being clear or upfront about this kind of work, I feel, is good. I will even comment code like this with why I’m doing it this way in case I need to update or rework later.

# We'll use these list with dplyr to assign a new variable
artist <- c(
  "Artist Housing", "Artist Live/Work Space"
)

disabled <- c(
  "People with Disabilities" 
)

family <- c(
  "Multfamily", "Multifamily", "Multifamily/Artists", "Multigfamily",
  "Mutifamily", "Inter-generational" 
)

senior <- c(
  "Senior", "Senior HUD 202", "Senior LGBTQ", "Seniors"
)

supportive <- c(
  "65+/Supportive", "Disabled/Homeless", "Supportive", "Supportive Housing",
  "Supportive/HIV/AIDS", "Supportive/Kinship Families", "Supportive/Males 18-24yrs.",
  "Supportive/Teenage Moms", "Supportive/Veterans", "Supportive/Youth/Kinship Families"
)

Using dplyr we will check if the property_type is in the named list; if it is, then we’ll assign the string after the ~ to the variable–I usually also try to catch errors by assigning anything left over to "error" to see what went wrong

housing %<>%
  mutate(property_category = case_when(
    property_type %in% artist ~ "Artist",
    property_type %in% disabled ~ "Disabled",
    property_type %in% family ~ "Family",
    property_type %in% senior ~ "Senior",
    property_type %in% supportive ~ "Supportive",
    property_type == "ARO" ~ "ARO", # what is ARO??
    TRUE ~ "error"
  )) 

Totals for property_category

housing %<>%
  group_by(property_category) %>%
  mutate(n_by_property_category = n())

Totals for management_company for each community

  • Group by the company and by the community
  • Create a variable with the count of that grouping
  • Organize by community name
  • Remove the grouping
  • Group by the community only
  • Create a variable with the count of that grouping
  • Remove the grouping
housing %<>% 
  group_by(management_company, community_area_name) %>% 
  mutate(n_by_management_company = n()) %>%
  arrange(community_area_name) %>%
  dplyr::ungroup() %>%
  group_by(community_area_name) %>%
  mutate(n_affordable_housing = n()) %>%
  dplyr::ungroup()

Join

  • Join data (on community area name)
    • geo_data all caps; use stringr::str_to_title() to correct
    • housing variable name too long; shorte to community to match geo_data
geo_data %<>%
  mutate(community = str_to_title(community))
housing %<>%
  rename(community = community_area_name)

Join and make sure the data returned still has the simple features class attribute

data <- left_join(geo_data, housing, by = "community")
"sf" %in% class(data)
[1] TRUE

Create maps

icons <- awesomeIcons(
  icon = "fa-home",
  library = "fa",
  markerColor = "orange",
  iconColor = "white"
)

leaflet(data) %>%
  addTiles(mapbox) %>%
  addPolygons(
    fillColor = "grey",
    weigh = 1.5,
    fillOpacity = 0.7,
    smoothFactor = 0.5,
    color = "white",
    label = ~community) %>%
  addAwesomeMarkers(
    icon = icons,
    lng = ~data$longitude, lat = ~data$latitude)
Data contains 16 rows with either missing or invalid lat/lon values and will be ignored

NA
LS0tCnRpdGxlOiAiU2FtcGxlIGFuYWx5c2lzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIFBhY2thZ2VzCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoc2YpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KGxlYWZsZXQpCmBgYAoKIyMgRnVuY3Rpb25zCgpgYGB7cn0KYCU8PiVgIDwtIG1hZ3JpdHRyOjpgJTw+JWAKYGBgCgojIyBBUEkgdG9rZW5zCgpgYGB7cn0KbWFwYm94IDwtICJodHRwczovL2FwaS5tYXBib3guY29tL3N0eWxlcy92MS9yb2JlcnRtaXRjaGVsbHYvY2lwcjd0ZWljMDAxYWVrbTcyZG5lbXBhbi90aWxlcy8yNTYve3p9L3t4fS97eX1AMng/YWNjZXNzX3Rva2VuPXBrLmV5SjFJam9pY205aVpYSjBiV2wwWTJobGJHeDJJaXdpWVNJNkltTnBjSEkyY1hGbmJUQTNNSFJtYkc1ak5XSnpNekp0YURRaWZRLnZ0dmdMb2tjY19FSmduV1ZQTDR2WHciCmBgYAoKIyBEYXRhCgojIyBSZWFkIHRoZSBhZmZvcmRhYmxlIGhvdXNpbmcgZGF0YQoKYGBge3J9CmhvdXNpbmcgPC0gcmVhZF9jc3YoIi4uL2RhdGEvcmF3L0FmZm9yZGFibGVfUmVudGFsX0hvdXNpbmdfRGV2ZWxvcG1lbnRzLmNzdiIpICU+JQogIGphbml0b3I6OmNsZWFuX25hbWVzKCkKYGBgCgpfX0NoZWNrIGZvciBwcm9ibGVtc19fCmBgYHtyfQpwcm9ibGVtcyhob3VzaW5nKQpgYGAKCiMjIFJlYWQgdGhlIGdlbyBkYXRhCgpgYGB7cn0KZ2VvX2RhdGEgPC0gcmVhZF9zZigKICBkc24gPSAiLi4vZGF0YS9nZW8vY2hpY2Fnb19ib3VuZGFyaWVzX2NvbW11bml0eV9hcmVhcy5nZW9qc29uIiwKICBsYXllciA9ICJjaGljYWdvX2JvdW5kYXJpZXNfY29tbXVuaXR5X2FyZWFzIgopCmBgYAoKIyBUaWR5CgojIyBHZXQgc3VtbWFyeSB0b3RhbHMKCiogQmVmb3JlIGpvaW5pbmcgZGF0YSwgd2UgbmVlZCB0b3RhbHMgZm9yIHRoZSBtYXAsIGUuZy4sIGhvdyBtYW55IHZldGVyYW5zIHByb2plY3RzIGluIGEgcGFydGljdWxhciBjb21tdW5pdHk/CiAgKyBUaGVyZSBhcmUgMjQgZGlmZmVyZW50IHByb3BlcnR5IHR5cGVzOyBtb3N0IG9mIGl0IGlzIHNlbmlvciBhbmQgZmFtaWx5LCBtYXliZSB3ZSBjYW4gc2ltcGxpZnk/CiAgKyBUaGVyZSBhcmUgMTQ2IGRpZmZlcmVudCBkZXZlbG9wcGVycyB3aXRoIHRoZSB0b3AgMTcgYWxsIGRldmVsb3BwaW5nIGFuZCBtYW5hZ2luZyA1KyBhZmZvcmRhYmxlIGhvdXNpbmcgcHJvcGVydGllcwoKIyMjIExvb2sgZm9yIGNhdGVnb3JpZXMKCmBgYHtyfQpob3VzaW5nICU+JSAKICBjb3VudChwcm9wZXJ0eV90eXBlKSAKYGBgCgo+IFRoaXMgaXMgc3ViamVjdGl2ZSwgYnV0IGl0IGlzIGFsc28gaW1wb3J0YW50IHRvIHJlbWVtYmVyIHRoYXQgX2FsbF8gY2xhc3NpZmljYXRpb24gb3IgY2F0ZWdvcml6YXRpb24gaXMgc3ViamVjdGl2ZS0taXQncyBhIGNyaXRpY2FsIGNob2ljZSBhbmQgaW1wb3J0YW50IHRvIHJlbWVtYmVyIHdoZW4gd29ya2luZyB3aXRoIGRhdGEuIEJlaW5nIGNsZWFyIG9yIHVwZnJvbnQgYWJvdXQgdGhpcyBraW5kIG9mIHdvcmssIEkgZmVlbCwgaXMgZ29vZC4gSSB3aWxsIGV2ZW4gY29tbWVudCBjb2RlIGxpa2UgdGhpcyB3aXRoIHdoeSBJJ20gZG9pbmcgaXQgdGhpcyB3YXkgaW4gY2FzZSBJIG5lZWQgdG8gdXBkYXRlIG9yIHJld29yayBsYXRlci4KCmBgYHtyfQojIFdlJ2xsIHVzZSB0aGVzZSBsaXN0IHdpdGggZHBseXIgdG8gYXNzaWduIGEgbmV3IHZhcmlhYmxlCmFydGlzdCA8LSBjKAogICJBcnRpc3QgSG91c2luZyIsICJBcnRpc3QgTGl2ZS9Xb3JrIFNwYWNlIgopCgpkaXNhYmxlZCA8LSBjKAogICJQZW9wbGUgd2l0aCBEaXNhYmlsaXRpZXMiIAopCgpmYW1pbHkgPC0gYygKICAiTXVsdGZhbWlseSIsICJNdWx0aWZhbWlseSIsICJNdWx0aWZhbWlseS9BcnRpc3RzIiwgIk11bHRpZ2ZhbWlseSIsCiAgIk11dGlmYW1pbHkiLCAiSW50ZXItZ2VuZXJhdGlvbmFsIiAKKQoKc2VuaW9yIDwtIGMoCiAgIlNlbmlvciIsICJTZW5pb3IgSFVEIDIwMiIsICJTZW5pb3IgTEdCVFEiLCAiU2VuaW9ycyIKKQoKc3VwcG9ydGl2ZSA8LSBjKAogICI2NSsvU3VwcG9ydGl2ZSIsICJEaXNhYmxlZC9Ib21lbGVzcyIsICJTdXBwb3J0aXZlIiwgIlN1cHBvcnRpdmUgSG91c2luZyIsCiAgIlN1cHBvcnRpdmUvSElWL0FJRFMiLCAiU3VwcG9ydGl2ZS9LaW5zaGlwIEZhbWlsaWVzIiwgIlN1cHBvcnRpdmUvTWFsZXMgMTgtMjR5cnMuIiwKICAiU3VwcG9ydGl2ZS9UZWVuYWdlIE1vbXMiLCAiU3VwcG9ydGl2ZS9WZXRlcmFucyIsICJTdXBwb3J0aXZlL1lvdXRoL0tpbnNoaXAgRmFtaWxpZXMiCikKYGBgCgpfX1VzaW5nIGBkcGx5cmAgd2Ugd2lsbCBjaGVjayBpZiB0aGUgYHByb3BlcnR5X3R5cGVgIGlzIGluIHRoZSBuYW1lZCBsaXN0OyBpZiBpdCBpcywgdGhlbiB3ZSdsbCBhc3NpZ24gdGhlIHN0cmluZyBfYWZ0ZXJfIHRoZSBgfmAgdG8gdGhlIHZhcmlhYmxlLS1JIHVzdWFsbHkgYWxzbyB0cnkgdG8gY2F0Y2ggZXJyb3JzIGJ5IGFzc2lnbmluZyBhbnl0aGluZyBsZWZ0IG92ZXIgdG8gYCJlcnJvciJgIHRvIHNlZSB3aGF0IHdlbnQgd3JvbmdfXwpgYGB7cn0KaG91c2luZyAlPD4lCiAgbXV0YXRlKHByb3BlcnR5X2NhdGVnb3J5ID0gY2FzZV93aGVuKAogICAgcHJvcGVydHlfdHlwZSAlaW4lIGFydGlzdCB+ICJBcnRpc3QiLAogICAgcHJvcGVydHlfdHlwZSAlaW4lIGRpc2FibGVkIH4gIkRpc2FibGVkIiwKICAgIHByb3BlcnR5X3R5cGUgJWluJSBmYW1pbHkgfiAiRmFtaWx5IiwKICAgIHByb3BlcnR5X3R5cGUgJWluJSBzZW5pb3IgfiAiU2VuaW9yIiwKICAgIHByb3BlcnR5X3R5cGUgJWluJSBzdXBwb3J0aXZlIH4gIlN1cHBvcnRpdmUiLAogICAgcHJvcGVydHlfdHlwZSA9PSAiQVJPIiB+ICJBUk8iLCAjIHdoYXQgaXMgQVJPPz8KICAgIFRSVUUgfiAiZXJyb3IiCiAgKSkgCmBgYAoKIyMjIFRvdGFscyBmb3IgYHByb3BlcnR5X2NhdGVnb3J5YAoKYGBge3J9CmhvdXNpbmcgJTw+JQogIGdyb3VwX2J5KHByb3BlcnR5X2NhdGVnb3J5KSAlPiUKICBtdXRhdGUobl9ieV9wcm9wZXJ0eV9jYXRlZ29yeSA9IG4oKSkKYGBgCgojIyMgVG90YWxzIGZvciBgbWFuYWdlbWVudF9jb21wYW55YCBmb3IgZWFjaCBjb21tdW5pdHkKCiogR3JvdXAgYnkgdGhlIGNvbXBhbnkgYW5kIGJ5IHRoZSBjb21tdW5pdHkKKiBDcmVhdGUgYSB2YXJpYWJsZSB3aXRoIHRoZSBjb3VudCBvZiB0aGF0IGdyb3VwaW5nCiogT3JnYW5pemUgYnkgY29tbXVuaXR5IG5hbWUKKiBSZW1vdmUgdGhlIGdyb3VwaW5nCiogR3JvdXAgYnkgdGhlIGNvbW11bml0eSBvbmx5CiogQ3JlYXRlIGEgdmFyaWFibGUgd2l0aCB0aGUgY291bnQgb2YgdGhhdCBncm91cGluZwoqIFJlbW92ZSB0aGUgZ3JvdXBpbmcKCmBgYHtyfQpob3VzaW5nICU8PiUgCiAgZ3JvdXBfYnkobWFuYWdlbWVudF9jb21wYW55LCBjb21tdW5pdHlfYXJlYV9uYW1lKSAlPiUgCiAgbXV0YXRlKG5fYnlfbWFuYWdlbWVudF9jb21wYW55ID0gbigpKSAlPiUKICBhcnJhbmdlKGNvbW11bml0eV9hcmVhX25hbWUpICU+JQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lCiAgZ3JvdXBfYnkoY29tbXVuaXR5X2FyZWFfbmFtZSkgJT4lCiAgbXV0YXRlKG5fYWZmb3JkYWJsZV9ob3VzaW5nID0gbigpKSAlPiUKICBkcGx5cjo6dW5ncm91cCgpCmBgYAoKIyMgSm9pbgoKKiBKb2luIGRhdGEgKG9uIGNvbW11bml0eSBhcmVhIG5hbWUpCiAgKyBgZ2VvX2RhdGFgIGFsbCBjYXBzOyB1c2UgYHN0cmluZ3I6OnN0cl90b190aXRsZSgpYCB0byBjb3JyZWN0CiAgKyBgaG91c2luZ2AgdmFyaWFibGUgbmFtZSB0b28gbG9uZzsgc2hvcnRlIHRvIGBjb21tdW5pdHlgIHRvIG1hdGNoIGBnZW9fZGF0YWAKCmBgYHtyfQpnZW9fZGF0YSAlPD4lCiAgbXV0YXRlKGNvbW11bml0eSA9IHN0cl90b190aXRsZShjb21tdW5pdHkpKQpgYGAKCmBgYHtyfQpob3VzaW5nICU8PiUKICByZW5hbWUoY29tbXVuaXR5ID0gY29tbXVuaXR5X2FyZWFfbmFtZSkKYGBgCgpfX0pvaW4gYW5kIG1ha2Ugc3VyZSB0aGUgZGF0YSByZXR1cm5lZCBzdGlsbCBoYXMgdGhlIHNpbXBsZSBmZWF0dXJlcyBjbGFzcyBhdHRyaWJ1dGVfXwpgYGB7cn0KZGF0YSA8LSBsZWZ0X2pvaW4oZ2VvX2RhdGEsIGhvdXNpbmcsIGJ5ID0gImNvbW11bml0eSIpCiJzZiIgJWluJSBjbGFzcyhkYXRhKQpgYGAKCiMgQ3JlYXRlIG1hcHMKCmBgYHtyfQppY29ucyA8LSBhd2Vzb21lSWNvbnMoCiAgaWNvbiA9ICJmYS1ob21lIiwKICBsaWJyYXJ5ID0gImZhIiwKICBtYXJrZXJDb2xvciA9ICJvcmFuZ2UiLAogIGljb25Db2xvciA9ICJ3aGl0ZSIKKQoKbGVhZmxldChkYXRhKSAlPiUKICBhZGRUaWxlcyhtYXBib3gpICU+JQogIGFkZFBvbHlnb25zKAogICAgZmlsbENvbG9yID0gImdyZXkiLAogICAgd2VpZ2ggPSAxLjUsCiAgICBmaWxsT3BhY2l0eSA9IDAuNywKICAgIHNtb290aEZhY3RvciA9IDAuNSwKICAgIGNvbG9yID0gIndoaXRlIiwKICAgIGxhYmVsID0gfmNvbW11bml0eSkgJT4lCiAgYWRkQXdlc29tZU1hcmtlcnMoCiAgICBpY29uID0gaWNvbnMsCiAgICBsbmcgPSB+ZGF0YSRsb25naXR1ZGUsIGxhdCA9IH5kYXRhJGxhdGl0dWRlKQogIApgYGAKCg==